/*
 ------------------------------------------------------------------------------
 Copyright (C) 1996-2001 Id Software, Inc.

 This file is part of the Quake source code.

 The Quake source code is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or (at your
 option) any later version.

 The Quake source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along with
 the Quake source code; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ------------------------------------------------------------------------------
*/


//
// matrix.h - matrix math library
//


#ifndef __MATH_MATRIX_H__
#define __MATH_MATRIX_H__


extern glqMat3		mat3_identity;
extern glqMat4		mat4_identity;

/*
 ==============================================================================

 3x3 MATRIX

 ==============================================================================
*/

class glqMat3 {
private:
	glqVec3			m[3];

public:
					glqMat3 (void);
	explicit		glqMat3 (const glqVec3 &x, const glqVec3 &y, const glqVec3 &z);
	explicit		glqMat3 (const float xx, const float xy, const float xz, const float yx, const float yy, const float yz, const float zx, const float zy, const float zz);

	const glqVec3 &	operator [] (const int index) const;
	glqVec3 &		operator [] (const int index);

	glqMat3 &		operator = (const glqMat3 &mat);
	bool			operator == (const glqMat3 &mat) const;
	bool			operator != (const glqMat3 &mat) const;

	glqMat3			operator * (const glqMat3 &mat) const;
	glqVec3			operator * (const glqVec3 &vec) const;

	glqMat3 &		operator *= (const glqMat3 &mat);

	void			Set (const glqVec3 &x, const glqVec3 &y, const glqVec3 &z);
	void			Set (const float xx, const float xy, const float xz, const float yx, const float yy, const float yz, const float zx, const float zy, const float zz);
	void			Identity (void);
	bool			IsIdentity (void) const;
	glqMat3			Transpose (void) const;
	void			TransposeSelf (void);
	glqMat3			Inverse (void) const;
	void			InverseSelf (void);
	glqMat3			Multiply (const glqMat3 &mat) const;
	glqMat3			TransposeMultiply (const glqMat3 &mat) const;
	void			ProjectVector (const glqVec3 &in, glqVec3 &out) const;
	void			UnprojectVector (const glqVec3 &in, glqVec3 &out) const;

	const float *	ToFloatPtr (void) const;
	float *			ToFloatPtr (void);

	glqAngles		ToAngles (void) const;
	glqQuat			ToQuat (void) const;
	glqMat4			ToMat4 (void) const;
	const char *	ToString (int precision = 2) const;
};

INLINE glqMat3::glqMat3 (void){

}

INLINE glqMat3::glqMat3 (const glqVec3 &x, const glqVec3 &y, const glqVec3 &z){

	m[0] = x;
	m[1] = y;
	m[2] = z;
}

INLINE glqMat3::glqMat3 (const float xx, const float xy, const float xz, const float yx, const float yy, const float yz, const float zx, const float zy, const float zz){

	m[0][0] = xx;
	m[0][1] = xy;
	m[0][2] = xz;
	m[1][0] = yx;
	m[1][1] = yy;
	m[1][2] = yz;
	m[2][0] = zx;
	m[2][1] = zy;
	m[2][2] = zz;
}

INLINE const glqVec3 &glqMat3::operator [] (const int index) const {

	return m[index];
}

INLINE glqVec3 &glqMat3::operator [] (const int index){

	return m[index];
}

INLINE glqMat3 &glqMat3::operator = (const glqMat3 &mat){

	m[0] = mat[0];
	m[1] = mat[1];
	m[2] = mat[2];

	return *this;
}

INLINE bool glqMat3::operator == (const glqMat3 &mat) const {

	if (m[0] != mat[0] || m[1] != mat[1] || m[2] != mat[2])
		return false;

	return true;
}

INLINE bool glqMat3::operator != (const glqMat3 &mat) const {

	if (m[0] == mat[0] && m[1] == mat[1] && m[2] == mat[2])
		return false;

	return true;
}

INLINE glqMat3 glqMat3::operator * (const glqMat3 &mat) const {

	glqMat3	result;

	result[0][0] = m[0][0] * mat[0][0] + m[0][1] * mat[1][0] + m[0][2] * mat[2][0];
	result[0][1] = m[0][0] * mat[0][1] + m[0][1] * mat[1][1] + m[0][2] * mat[2][1];
	result[0][2] = m[0][0] * mat[0][2] + m[0][1] * mat[1][2] + m[0][2] * mat[2][2];
	result[1][0] = m[1][0] * mat[0][0] + m[1][1] * mat[1][0] + m[1][2] * mat[2][0];
	result[1][1] = m[1][0] * mat[0][1] + m[1][1] * mat[1][1] + m[1][2] * mat[2][1];
	result[1][2] = m[1][0] * mat[0][2] + m[1][1] * mat[1][2] + m[1][2] * mat[2][2];
	result[2][0] = m[2][0] * mat[0][0] + m[2][1] * mat[1][0] + m[2][2] * mat[2][0];
	result[2][1] = m[2][0] * mat[0][1] + m[2][1] * mat[1][1] + m[2][2] * mat[2][1];
	result[2][2] = m[2][0] * mat[0][2] + m[2][1] * mat[1][2] + m[2][2] * mat[2][2];

	return result;
}

INLINE glqVec3 glqMat3::operator * (const glqVec3 &vec) const {

	glqVec3	result;

	result[0] = vec[0] * m[0][0] + vec[1] * m[1][0] + vec[2] * m[2][0];
	result[1] = vec[0] * m[0][1] + vec[1] * m[1][1] + vec[2] * m[2][1];
	result[2] = vec[0] * m[0][2] + vec[1] * m[1][2] + vec[2] * m[2][2];

	return result;
}

INLINE glqMat3 &glqMat3::operator *= (const glqMat3 &mat){

	glqMat3	tmp;

	tmp[0][0] = m[0][0] * mat[0][0] + m[0][1] * mat[1][0] + m[0][2] * mat[2][0];
	tmp[0][1] = m[0][0] * mat[0][1] + m[0][1] * mat[1][1] + m[0][2] * mat[2][1];
	tmp[0][2] = m[0][0] * mat[0][2] + m[0][1] * mat[1][2] + m[0][2] * mat[2][2];
	tmp[1][0] = m[1][0] * mat[0][0] + m[1][1] * mat[1][0] + m[1][2] * mat[2][0];
	tmp[1][1] = m[1][0] * mat[0][1] + m[1][1] * mat[1][1] + m[1][2] * mat[2][1];
	tmp[1][2] = m[1][0] * mat[0][2] + m[1][1] * mat[1][2] + m[1][2] * mat[2][2];
	tmp[2][0] = m[2][0] * mat[0][0] + m[2][1] * mat[1][0] + m[2][2] * mat[2][0];
	tmp[2][1] = m[2][0] * mat[0][1] + m[2][1] * mat[1][1] + m[2][2] * mat[2][1];
	tmp[2][2] = m[2][0] * mat[0][2] + m[2][1] * mat[1][2] + m[2][2] * mat[2][2];

	m[0] = tmp[0];
	m[1] = tmp[1];
	m[2] = tmp[2];

	return *this;
}

INLINE void glqMat3::Set (const glqVec3 &x, const glqVec3 &y, const glqVec3 &z){

	m[0] = x;
	m[1] = y;
	m[2] = z;
}

INLINE void glqMat3::Set (const float xx, const float xy, const float xz, const float yx, const float yy, const float yz, const float zx, const float zy, const float zz){

	m[0][0] = xx;
	m[0][1] = xy;
	m[0][2] = xz;
	m[1][0] = yx;
	m[1][1] = yy;
	m[1][2] = yz;
	m[2][0] = zx;
	m[2][1] = zy;
	m[2][2] = zz;
}

INLINE void glqMat3::Identity (void){

	m[0][0] = 1.0f;
	m[0][1] = 0.0f;
	m[0][2] = 0.0f;
	m[1][0] = 0.0f;
	m[1][1] = 1.0f;
	m[1][2] = 0.0f;
	m[2][0] = 0.0f;
	m[2][1] = 0.0f;
	m[2][2] = 1.0f;
}

INLINE bool glqMat3::IsIdentity (void) const {

	if (m[0][0] != 1.0f || m[0][1] != 0.0f || m[0][2] != 0.0f)
		return false;
	if (m[1][0] != 0.0f || m[1][1] != 1.0f || m[1][2] != 0.0f)
		return false;
	if (m[2][0] != 0.0f || m[2][1] != 0.0f || m[2][2] != 1.0f)
		return false;

	return true;
}

INLINE glqMat3 glqMat3::Transpose (void) const {

	glqMat3	transpose;

	transpose[0][0] = m[0][0];
	transpose[0][1] = m[1][0];
	transpose[0][2] = m[2][0];
	transpose[1][0] = m[0][1];
	transpose[1][1] = m[1][1];
	transpose[1][2] = m[2][1];
	transpose[2][0] = m[0][2];
	transpose[2][1] = m[1][2];
	transpose[2][2] = m[2][2];

	return transpose;
}

INLINE void glqMat3::TransposeSelf (void){

	float	tmp;

	tmp = m[0][1];
	m[0][1] = m[1][0];
	m[1][0] = tmp;

	tmp = m[0][2];
	m[0][2] = m[2][0];
	m[2][0] = tmp;

	tmp = m[1][2];
	m[1][2] = m[2][1];
	m[2][1] = tmp;
}

INLINE glqMat3 glqMat3::Multiply (const glqMat3 &mat) const {

	glqMat3	result;

	result[0][0] = m[0][0] * mat[0][0] + m[0][1] * mat[1][0] + m[0][2] * mat[2][0];
	result[0][1] = m[0][0] * mat[0][1] + m[0][1] * mat[1][1] + m[0][2] * mat[2][1];
	result[0][2] = m[0][0] * mat[0][2] + m[0][1] * mat[1][2] + m[0][2] * mat[2][2];
	result[1][0] = m[1][0] * mat[0][0] + m[1][1] * mat[1][0] + m[1][2] * mat[2][0];
	result[1][1] = m[1][0] * mat[0][1] + m[1][1] * mat[1][1] + m[1][2] * mat[2][1];
	result[1][2] = m[1][0] * mat[0][2] + m[1][1] * mat[1][2] + m[1][2] * mat[2][2];
	result[2][0] = m[2][0] * mat[0][0] + m[2][1] * mat[1][0] + m[2][2] * mat[2][0];
	result[2][1] = m[2][0] * mat[0][1] + m[2][1] * mat[1][1] + m[2][2] * mat[2][1];
	result[2][2] = m[2][0] * mat[0][2] + m[2][1] * mat[1][2] + m[2][2] * mat[2][2];

	return result;
}

INLINE glqMat3 glqMat3::TransposeMultiply (const glqMat3 &mat) const {

	glqMat3	result;

	result[0][0] = m[0][0] * mat[0][0] + m[0][1] * mat[0][1] + m[0][2] * mat[0][2];
	result[0][1] = m[0][0] * mat[1][0] + m[0][1] * mat[1][1] + m[0][2] * mat[1][2];
	result[0][2] = m[0][0] * mat[2][0] + m[0][1] * mat[2][1] + m[0][2] * mat[2][2];
	result[1][0] = m[1][0] * mat[0][0] + m[1][1] * mat[0][1] + m[1][2] * mat[0][2];
	result[1][1] = m[1][0] * mat[1][0] + m[1][1] * mat[1][1] + m[1][2] * mat[1][2];
	result[1][2] = m[1][0] * mat[2][0] + m[1][1] * mat[2][1] + m[1][2] * mat[2][2];
	result[2][0] = m[2][0] * mat[0][0] + m[2][1] * mat[0][1] + m[2][2] * mat[0][2];
	result[2][1] = m[2][0] * mat[1][0] + m[2][1] * mat[1][1] + m[2][2] * mat[1][2];
	result[2][2] = m[2][0] * mat[2][0] + m[2][1] * mat[2][1] + m[2][2] * mat[2][2];

	return result;
}

INLINE void glqMat3::ProjectVector (const glqVec3 &in, glqVec3 &out) const {

	out[0] = in[0] * m[0][0] + in[1] * m[0][1] + in[2] * m[0][2];
	out[1] = in[0] * m[1][0] + in[1] * m[1][1] + in[2] * m[1][2];
	out[2] = in[0] * m[2][0] + in[1] * m[2][1] + in[2] * m[2][2];
}

INLINE void glqMat3::UnprojectVector (const glqVec3 &in, glqVec3 &out) const {

	out[0] = in[0] * m[0][0] + in[1] * m[1][0] + in[2] * m[2][0];
	out[1] = in[0] * m[0][1] + in[1] * m[1][1] + in[2] * m[2][1];
	out[2] = in[0] * m[0][2] + in[1] * m[1][2] + in[2] * m[2][2];
}

INLINE const float *glqMat3::ToFloatPtr (void) const {

	return m[0].ToFloatPtr();
}

INLINE float *glqMat3::ToFloatPtr (void){

	return m[0].ToFloatPtr();
}

/*
 ==============================================================================

 4x4 MATRIX

 ==============================================================================
*/

class glqMat4 {
private:
	glqVec4			m[4];

public:
					glqMat4 (void);
	explicit		glqMat4 (const glqMat3 &rotation, const glqVec3 &translation);
	explicit		glqMat4 (const glqVec4 &x, const glqVec4 &y, const glqVec4 &z, const glqVec4 &w);
	explicit		glqMat4 (const float xx, const float xy, const float xz, const float xw, const float yx, const float yy, const float yz, const float yw, const float zx, const float zy, const float zz, const float zw, const float wx, const float wy, const float wz, const float ww);

	const glqVec4 &	operator [] (const int index) const;
	glqVec4 &		operator [] (const int index);

	glqMat4 &		operator = (const glqMat4 &mat);
	bool			operator == (const glqMat4 &mat) const;
	bool			operator != (const glqMat4 &mat) const;

	glqMat4			operator * (const glqMat4 &mat) const;
	glqVec4			operator * (const glqVec4 &vec) const;

	glqMat4 &		operator *= (const glqMat4 &mat);

	void			Set (const glqMat3 &rotation, const glqVec3 &translation);
	void			Set (const glqVec4 &x, const glqVec4 &y, const glqVec4 &z, const glqVec4 &w);
	void			Set (const float xx, const float xy, const float xz, const float xw, const float yx, const float yy, const float yz, const float yw, const float zx, const float zy, const float zz, const float zw, const float wx, const float wy, const float wz, const float ww);
	void			Identity (void);
	bool			IsIdentity (void) const;
	glqMat4			Transpose (void) const;
	void			TransposeSelf (void);
	glqMat4			Inverse (void) const;
	void			InverseSelf (void);
	void			Scale (const float x, const float y, const float z);
	void			Translate (const float x, const float y, const float z);
	void			Shear (const float x, const float y, const float z);
	void			Rotate (const float angle, const float x, const float y, const float z);
	glqMat4			Multiply (const glqMat4 &mat) const;
	glqMat4			Multiply (const glqMat3 &rotation, const glqVec3 &translation) const;
	glqMat4			TransposeMultiply (const glqMat4 &mat) const;
	glqMat4			TransposeMultiply (const glqMat3 &rotation, const glqVec3 &translation) const;
	void			ProjectVector (const glqVec4 &in, glqVec4 &out) const;
	void			UnprojectVector (const glqVec4 &in, glqVec4 &out) const;

	const float *	ToFloatPtr (void) const;
	float *			ToFloatPtr (void);

	glqMat3			ToMat3 (void) const;
	const char *	ToString (int precision = 2) const;
};

INLINE glqMat4::glqMat4 (void){

}

INLINE glqMat4::glqMat4 (const glqMat3 &rotation, const glqVec3 &translation){

	m[0][0] = rotation[0][0];
	m[0][1] = rotation[0][1];
	m[0][2] = rotation[0][2];
	m[0][3] = 0.0f;
	m[1][0] = rotation[1][0];
	m[1][1] = rotation[1][1];
	m[1][2] = rotation[1][2];
	m[1][3] = 0.0f;
	m[2][0] = rotation[2][0];
	m[2][1] = rotation[2][1];
	m[2][2] = rotation[2][2];
	m[2][3] = 0.0f;
	m[3][0] = translation[0];
	m[3][1] = translation[1];
	m[3][2] = translation[2];
	m[3][3] = 1.0f;
}

INLINE glqMat4::glqMat4 (const glqVec4 &x, const glqVec4 &y, const glqVec4 &z, const glqVec4 &w){

	m[0] = x;
	m[1] = y;
	m[2] = z;
	m[3] = w;
}

INLINE glqMat4::glqMat4 (const float xx, const float xy, const float xz, const float xw, const float yx, const float yy, const float yz, const float yw, const float zx, const float zy, const float zz, const float zw, const float wx, const float wy, const float wz, const float ww){

	m[0][0] = xx;
	m[0][1] = xy;
	m[0][2] = xz;
	m[0][3] = xw;
	m[1][0] = yx;
	m[1][1] = yy;
	m[1][2] = yz;
	m[1][3] = yw;
	m[2][0] = zx;
	m[2][1] = zy;
	m[2][2] = zz;
	m[2][3] = zw;
	m[3][0] = wx;
	m[3][1] = wy;
	m[3][2] = wz;
	m[3][3] = ww;
}

INLINE const glqVec4 &glqMat4::operator [] (const int index) const {

	return m[index];
}

INLINE glqVec4 &glqMat4::operator [] (const int index){

	return m[index];
}

INLINE glqMat4 &glqMat4::operator = (const glqMat4 &mat){

	m[0] = mat[0];
	m[1] = mat[1];
	m[2] = mat[2];
	m[3] = mat[3];

	return *this;
}

INLINE bool glqMat4::operator == (const glqMat4 &mat) const {

	if (m[0] != mat[0] || m[1] != mat[1] || m[2] != mat[2] || m[3] != mat[3])
		return false;

	return true;
}

INLINE bool glqMat4::operator != (const glqMat4 &mat) const {

	if (m[0] == mat[0] && m[1] == mat[1] && m[2] == mat[2] && m[3] == mat[3])
		return false;

	return true;
}

INLINE glqMat4 glqMat4::operator * (const glqMat4 &mat) const {

	glqMat4	result;

	result[0][0] = m[0][0] * mat[0][0] + m[1][0] * mat[0][1] + m[2][0] * mat[0][2] + m[3][0] * mat[0][3];
	result[0][1] = m[0][1] * mat[0][0] + m[1][1] * mat[0][1] + m[2][1] * mat[0][2] + m[3][1] * mat[0][3];
	result[0][2] = m[0][2] * mat[0][0] + m[1][2] * mat[0][1] + m[2][2] * mat[0][2] + m[3][2] * mat[0][3];
	result[0][3] = m[0][3] * mat[0][0] + m[1][3] * mat[0][1] + m[2][3] * mat[0][2] + m[3][3] * mat[0][3];
	result[1][0] = m[0][0] * mat[1][0] + m[1][0] * mat[1][1] + m[2][0] * mat[1][2] + m[3][0] * mat[1][3];
	result[1][1] = m[0][1] * mat[1][0] + m[1][1] * mat[1][1] + m[2][1] * mat[1][2] + m[3][1] * mat[1][3];
	result[1][2] = m[0][2] * mat[1][0] + m[1][2] * mat[1][1] + m[2][2] * mat[1][2] + m[3][2] * mat[1][3];
	result[1][3] = m[0][3] * mat[1][0] + m[1][3] * mat[1][1] + m[2][3] * mat[1][2] + m[3][3] * mat[1][3];
	result[2][0] = m[0][0] * mat[2][0] + m[1][0] * mat[2][1] + m[2][0] * mat[2][2] + m[3][0] * mat[2][3];
	result[2][1] = m[0][1] * mat[2][0] + m[1][1] * mat[2][1] + m[2][1] * mat[2][2] + m[3][1] * mat[2][3];
	result[2][2] = m[0][2] * mat[2][0] + m[1][2] * mat[2][1] + m[2][2] * mat[2][2] + m[3][2] * mat[2][3];
	result[2][3] = m[0][3] * mat[2][0] + m[1][3] * mat[2][1] + m[2][3] * mat[2][2] + m[3][3] * mat[2][3];
	result[3][0] = m[0][0] * mat[3][0] + m[1][0] * mat[3][1] + m[2][0] * mat[3][2] + m[3][0] * mat[3][3];
	result[3][1] = m[0][1] * mat[3][0] + m[1][1] * mat[3][1] + m[2][1] * mat[3][2] + m[3][1] * mat[3][3];
	result[3][2] = m[0][2] * mat[3][0] + m[1][2] * mat[3][1] + m[2][2] * mat[3][2] + m[3][2] * mat[3][3];
	result[3][3] = m[0][3] * mat[3][0] + m[1][3] * mat[3][1] + m[2][3] * mat[3][2] + m[3][3] * mat[3][3];

	return result;
}

INLINE glqVec4 glqMat4::operator * (const glqVec4 &vec) const {

	glqVec4	result;

	result[0] = vec[0] * m[0][0] + vec[1] * m[1][0] + vec[2] * m[2][0] + vec[3] * m[3][0];
	result[1] = vec[0] * m[0][1] + vec[1] * m[1][1] + vec[2] * m[2][1] + vec[3] * m[3][1];
	result[2] = vec[0] * m[0][2] + vec[1] * m[1][2] + vec[2] * m[2][2] + vec[3] * m[3][2];
	result[3] = vec[0] * m[0][3] + vec[1] * m[1][3] + vec[2] * m[2][3] + vec[3] * m[3][3];

	return result;
}

INLINE glqMat4 &glqMat4::operator *= (const glqMat4 &mat){

	glqMat4	tmp;

	tmp[0][0] = m[0][0] * mat[0][0] + m[1][0] * mat[0][1] + m[2][0] * mat[0][2] + m[3][0] * mat[0][3];
	tmp[0][1] = m[0][1] * mat[0][0] + m[1][1] * mat[0][1] + m[2][1] * mat[0][2] + m[3][1] * mat[0][3];
	tmp[0][2] = m[0][2] * mat[0][0] + m[1][2] * mat[0][1] + m[2][2] * mat[0][2] + m[3][2] * mat[0][3];
	tmp[0][3] = m[0][3] * mat[0][0] + m[1][3] * mat[0][1] + m[2][3] * mat[0][2] + m[3][3] * mat[0][3];
	tmp[1][0] = m[0][0] * mat[1][0] + m[1][0] * mat[1][1] + m[2][0] * mat[1][2] + m[3][0] * mat[1][3];
	tmp[1][1] = m[0][1] * mat[1][0] + m[1][1] * mat[1][1] + m[2][1] * mat[1][2] + m[3][1] * mat[1][3];
	tmp[1][2] = m[0][2] * mat[1][0] + m[1][2] * mat[1][1] + m[2][2] * mat[1][2] + m[3][2] * mat[1][3];
	tmp[1][3] = m[0][3] * mat[1][0] + m[1][3] * mat[1][1] + m[2][3] * mat[1][2] + m[3][3] * mat[1][3];
	tmp[2][0] = m[0][0] * mat[2][0] + m[1][0] * mat[2][1] + m[2][0] * mat[2][2] + m[3][0] * mat[2][3];
	tmp[2][1] = m[0][1] * mat[2][0] + m[1][1] * mat[2][1] + m[2][1] * mat[2][2] + m[3][1] * mat[2][3];
	tmp[2][2] = m[0][2] * mat[2][0] + m[1][2] * mat[2][1] + m[2][2] * mat[2][2] + m[3][2] * mat[2][3];
	tmp[2][3] = m[0][3] * mat[2][0] + m[1][3] * mat[2][1] + m[2][3] * mat[2][2] + m[3][3] * mat[2][3];
	tmp[3][0] = m[0][0] * mat[3][0] + m[1][0] * mat[3][1] + m[2][0] * mat[3][2] + m[3][0] * mat[3][3];
	tmp[3][1] = m[0][1] * mat[3][0] + m[1][1] * mat[3][1] + m[2][1] * mat[3][2] + m[3][1] * mat[3][3];
	tmp[3][2] = m[0][2] * mat[3][0] + m[1][2] * mat[3][1] + m[2][2] * mat[3][2] + m[3][2] * mat[3][3];
	tmp[3][3] = m[0][3] * mat[3][0] + m[1][3] * mat[3][1] + m[2][3] * mat[3][2] + m[3][3] * mat[3][3];

	m[0] = tmp[0];
	m[1] = tmp[1];
	m[2] = tmp[2];
	m[3] = tmp[3];

	return *this;
}

INLINE void glqMat4::Set (const glqMat3 &rotation, const glqVec3 &translation){

	m[0][0] = rotation[0][0];
	m[0][1] = rotation[0][1];
	m[0][2] = rotation[0][2];
	m[0][3] = 0.0f;
	m[1][0] = rotation[1][0];
	m[1][1] = rotation[1][1];
	m[1][2] = rotation[1][2];
	m[1][3] = 0.0f;
	m[2][0] = rotation[2][0];
	m[2][1] = rotation[2][1];
	m[2][2] = rotation[2][2];
	m[2][3] = 0.0f;
	m[3][0] = translation[0];
	m[3][1] = translation[1];
	m[3][2] = translation[2];
	m[3][3] = 1.0f;
}

INLINE void glqMat4::Set (const glqVec4 &x, const glqVec4 &y, const glqVec4 &z, const glqVec4 &w){

	m[0] = x;
	m[1] = y;
	m[2] = z;
	m[3] = w;
}

INLINE void glqMat4::Set (const float xx, const float xy, const float xz, const float xw, const float yx, const float yy, const float yz, const float yw, const float zx, const float zy, const float zz, const float zw, const float wx, const float wy, const float wz, const float ww){

	m[0][0] = xx;
	m[0][1] = xy;
	m[0][2] = xz;
	m[0][3] = xw;
	m[1][0] = yx;
	m[1][1] = yy;
	m[1][2] = yz;
	m[1][3] = yw;
	m[2][0] = zx;
	m[2][1] = zy;
	m[2][2] = zz;
	m[2][3] = zw;
	m[3][0] = wx;
	m[3][1] = wy;
	m[3][2] = wz;
	m[3][3] = ww;
}

INLINE void glqMat4::Identity (void){

	m[0][0] = 1.0f;
	m[0][1] = 0.0f;
	m[0][2] = 0.0f;
	m[0][3] = 0.0f;
	m[1][0] = 0.0f;
	m[1][1] = 1.0f;
	m[1][2] = 0.0f;
	m[1][3] = 0.0f;
	m[2][0] = 0.0f;
	m[2][1] = 0.0f;
	m[2][2] = 1.0f;
	m[2][3] = 0.0f;
	m[3][0] = 0.0f;
	m[3][1] = 0.0f;
	m[3][2] = 0.0f;
	m[3][3] = 1.0f;
}

INLINE bool glqMat4::IsIdentity (void) const {

	if (m[0][0] != 1.0f || m[0][1] != 0.0f || m[0][2] != 0.0f || m[0][3] != 0.0f)
		return false;
	if (m[1][0] != 0.0f || m[1][1] != 1.0f || m[1][2] != 0.0f || m[1][3] != 0.0f)
		return false;
	if (m[2][0] != 0.0f || m[2][1] != 0.0f || m[2][2] != 1.0f || m[2][3] != 0.0f)
		return false;
	if (m[3][0] != 0.0f || m[3][1] != 0.0f || m[3][2] != 0.0f || m[3][3] != 1.0f)
		return false;

	return true;
}

INLINE glqMat4 glqMat4::Transpose (void) const {

	glqMat4	transpose;

	transpose[0][0] = m[0][0];
	transpose[0][1] = m[1][0];
	transpose[0][2] = m[2][0];
	transpose[0][3] = m[3][0];
	transpose[1][0] = m[0][1];
	transpose[1][1] = m[1][1];
	transpose[1][2] = m[2][1];
	transpose[1][3] = m[3][1];
	transpose[2][0] = m[0][2];
	transpose[2][1] = m[1][2];
	transpose[2][2] = m[2][2];
	transpose[2][3] = m[3][2];
	transpose[3][0] = m[0][3];
	transpose[3][1] = m[1][3];
	transpose[3][2] = m[2][3];
	transpose[3][3] = m[3][3];

	return transpose;
}

INLINE void glqMat4::TransposeSelf (void){

	float	tmp;

	tmp = m[0][1];
	m[0][1] = m[1][0];
	m[1][0] = tmp;

	tmp = m[0][2];
	m[0][2] = m[2][0];
	m[2][0] = tmp;

	tmp = m[0][3];
	m[0][3] = m[3][0];
	m[3][0] = tmp;

	tmp = m[1][2];
	m[1][2] = m[2][1];
	m[2][1] = tmp;

	tmp = m[1][3];
	m[1][3] = m[3][1];
	m[3][1] = tmp;

	tmp = m[2][3];
	m[2][3] = m[3][2];
	m[3][2] = tmp;
}

INLINE glqMat4 glqMat4::Multiply (const glqMat4 &mat) const {

	glqMat4	result;

	result[0][0] = m[0][0] * mat[0][0] + m[1][0] * mat[0][1] + m[2][0] * mat[0][2] + m[3][0] * mat[0][3];
	result[0][1] = m[0][1] * mat[0][0] + m[1][1] * mat[0][1] + m[2][1] * mat[0][2] + m[3][1] * mat[0][3];
	result[0][2] = m[0][2] * mat[0][0] + m[1][2] * mat[0][1] + m[2][2] * mat[0][2] + m[3][2] * mat[0][3];
	result[0][3] = m[0][3] * mat[0][0] + m[1][3] * mat[0][1] + m[2][3] * mat[0][2] + m[3][3] * mat[0][3];
	result[1][0] = m[0][0] * mat[1][0] + m[1][0] * mat[1][1] + m[2][0] * mat[1][2] + m[3][0] * mat[1][3];
	result[1][1] = m[0][1] * mat[1][0] + m[1][1] * mat[1][1] + m[2][1] * mat[1][2] + m[3][1] * mat[1][3];
	result[1][2] = m[0][2] * mat[1][0] + m[1][2] * mat[1][1] + m[2][2] * mat[1][2] + m[3][2] * mat[1][3];
	result[1][3] = m[0][3] * mat[1][0] + m[1][3] * mat[1][1] + m[2][3] * mat[1][2] + m[3][3] * mat[1][3];
	result[2][0] = m[0][0] * mat[2][0] + m[1][0] * mat[2][1] + m[2][0] * mat[2][2] + m[3][0] * mat[2][3];
	result[2][1] = m[0][1] * mat[2][0] + m[1][1] * mat[2][1] + m[2][1] * mat[2][2] + m[3][1] * mat[2][3];
	result[2][2] = m[0][2] * mat[2][0] + m[1][2] * mat[2][1] + m[2][2] * mat[2][2] + m[3][2] * mat[2][3];
	result[2][3] = m[0][3] * mat[2][0] + m[1][3] * mat[2][1] + m[2][3] * mat[2][2] + m[3][3] * mat[2][3];
	result[3][0] = m[0][0] * mat[3][0] + m[1][0] * mat[3][1] + m[2][0] * mat[3][2] + m[3][0] * mat[3][3];
	result[3][1] = m[0][1] * mat[3][0] + m[1][1] * mat[3][1] + m[2][1] * mat[3][2] + m[3][1] * mat[3][3];
	result[3][2] = m[0][2] * mat[3][0] + m[1][2] * mat[3][1] + m[2][2] * mat[3][2] + m[3][2] * mat[3][3];
	result[3][3] = m[0][3] * mat[3][0] + m[1][3] * mat[3][1] + m[2][3] * mat[3][2] + m[3][3] * mat[3][3];

	return result;
}

INLINE glqMat4 glqMat4::Multiply (const glqMat3 &rotation, const glqVec3 &translation) const {

	glqMat4	result;

	result[0][0] = m[0][0] * rotation[0][0] + m[1][0] * rotation[0][1] + m[2][0] * rotation[0][2];
	result[0][1] = m[0][1] * rotation[0][0] + m[1][1] * rotation[0][1] + m[2][1] * rotation[0][2];
	result[0][2] = m[0][2] * rotation[0][0] + m[1][2] * rotation[0][1] + m[2][2] * rotation[0][2];
	result[0][3] = m[0][3] * rotation[0][0] + m[1][3] * rotation[0][1] + m[2][3] * rotation[0][2];
	result[1][0] = m[0][0] * rotation[1][0] + m[1][0] * rotation[1][1] + m[2][0] * rotation[1][2];
	result[1][1] = m[0][1] * rotation[1][0] + m[1][1] * rotation[1][1] + m[2][1] * rotation[1][2];
	result[1][2] = m[0][2] * rotation[1][0] + m[1][2] * rotation[1][1] + m[2][2] * rotation[1][2];
	result[1][3] = m[0][3] * rotation[1][0] + m[1][3] * rotation[1][1] + m[2][3] * rotation[1][2];
	result[2][0] = m[0][0] * rotation[2][0] + m[1][0] * rotation[2][1] + m[2][0] * rotation[2][2];
	result[2][1] = m[0][1] * rotation[2][0] + m[1][1] * rotation[2][1] + m[2][1] * rotation[2][2];
	result[2][2] = m[0][2] * rotation[2][0] + m[1][2] * rotation[2][1] + m[2][2] * rotation[2][2];
	result[2][3] = m[0][3] * rotation[2][0] + m[1][3] * rotation[2][1] + m[2][3] * rotation[2][2];
	result[3][0] = m[0][0] * translation[0] + m[1][0] * translation[1] + m[2][0] * translation[2] + m[3][0];
	result[3][1] = m[0][1] * translation[0] + m[1][1] * translation[1] + m[2][1] * translation[2] + m[3][1];
	result[3][2] = m[0][2] * translation[0] + m[1][2] * translation[1] + m[2][2] * translation[2] + m[3][2];
	result[3][3] = m[0][3] * translation[0] + m[1][3] * translation[1] + m[2][3] * translation[2] + m[3][3];

	return result;
}

INLINE glqMat4 glqMat4::TransposeMultiply (const glqMat4 &mat) const {

	glqMat4	result;

	result[0][0] = m[0][0] * mat[0][0] + m[0][1] * mat[0][1] + m[0][2] * mat[0][2] + m[0][3] * mat[0][3];
	result[0][1] = m[1][0] * mat[0][0] + m[1][1] * mat[0][1] + m[1][2] * mat[0][2] + m[1][3] * mat[0][3];
	result[0][2] = m[2][0] * mat[0][0] + m[2][1] * mat[0][1] + m[2][2] * mat[0][2] + m[2][3] * mat[0][3];
	result[0][3] = m[3][0] * mat[0][0] + m[3][1] * mat[0][1] + m[3][2] * mat[0][2] + m[3][3] * mat[0][3];
	result[1][0] = m[0][0] * mat[1][0] + m[0][1] * mat[1][1] + m[0][2] * mat[1][2] + m[0][3] * mat[1][3];
	result[1][1] = m[1][0] * mat[1][0] + m[1][1] * mat[1][1] + m[1][2] * mat[1][2] + m[1][3] * mat[1][3];
	result[1][2] = m[2][0] * mat[1][0] + m[2][1] * mat[1][1] + m[2][2] * mat[1][2] + m[2][3] * mat[1][3];
	result[1][3] = m[3][0] * mat[1][0] + m[3][1] * mat[1][1] + m[3][2] * mat[1][2] + m[3][3] * mat[1][3];
	result[2][0] = m[0][0] * mat[2][0] + m[0][1] * mat[2][1] + m[0][2] * mat[2][2] + m[0][3] * mat[2][3];
	result[2][1] = m[1][0] * mat[2][0] + m[1][1] * mat[2][1] + m[1][2] * mat[2][2] + m[1][3] * mat[2][3];
	result[2][2] = m[2][0] * mat[2][0] + m[2][1] * mat[2][1] + m[2][2] * mat[2][2] + m[2][3] * mat[2][3];
	result[2][3] = m[3][0] * mat[2][0] + m[3][1] * mat[2][1] + m[3][2] * mat[2][2] + m[3][3] * mat[2][3];
	result[3][0] = m[0][0] * mat[3][0] + m[0][1] * mat[3][1] + m[0][2] * mat[3][2] + m[0][3] * mat[3][3];
	result[3][1] = m[1][0] * mat[3][0] + m[1][1] * mat[3][1] + m[1][2] * mat[3][2] + m[1][3] * mat[3][3];
	result[3][2] = m[2][0] * mat[3][0] + m[2][1] * mat[3][1] + m[2][2] * mat[3][2] + m[2][3] * mat[3][3];
	result[3][3] = m[3][0] * mat[3][0] + m[3][1] * mat[3][1] + m[3][2] * mat[3][2] + m[3][3] * mat[3][3];

	return result;
}

INLINE glqMat4 glqMat4::TransposeMultiply (const glqMat3 &rotation, const glqVec3 &translation) const {

	glqMat4	result;

	result[0][0] = m[0][0] * rotation[0][0] + m[0][1] * rotation[0][1] + m[0][2] * rotation[0][2];
	result[0][1] = m[1][0] * rotation[0][0] + m[1][1] * rotation[0][1] + m[1][2] * rotation[0][2];
	result[0][2] = m[2][0] * rotation[0][0] + m[2][1] * rotation[0][1] + m[2][2] * rotation[0][2];
	result[0][3] = m[3][0] * rotation[0][0] + m[3][1] * rotation[0][1] + m[3][2] * rotation[0][2];
	result[1][0] = m[0][0] * rotation[1][0] + m[0][1] * rotation[1][1] + m[0][2] * rotation[1][2];
	result[1][1] = m[1][0] * rotation[1][0] + m[1][1] * rotation[1][1] + m[1][2] * rotation[1][2];
	result[1][2] = m[2][0] * rotation[1][0] + m[2][1] * rotation[1][1] + m[2][2] * rotation[1][2];
	result[1][3] = m[3][0] * rotation[1][0] + m[3][1] * rotation[1][1] + m[3][2] * rotation[1][2];
	result[2][0] = m[0][0] * rotation[2][0] + m[0][1] * rotation[2][1] + m[0][2] * rotation[2][2];
	result[2][1] = m[1][0] * rotation[2][0] + m[1][1] * rotation[2][1] + m[1][2] * rotation[2][2];
	result[2][2] = m[2][0] * rotation[2][0] + m[2][1] * rotation[2][1] + m[2][2] * rotation[2][2];
	result[2][3] = m[3][0] * rotation[2][0] + m[3][1] * rotation[2][1] + m[3][2] * rotation[2][2];
	result[3][0] = m[0][0] * translation[0] + m[0][1] * translation[1] + m[0][2] * translation[2] + m[0][3];
	result[3][1] = m[1][0] * translation[0] + m[1][1] * translation[1] + m[1][2] * translation[2] + m[1][3];
	result[3][2] = m[2][0] * translation[0] + m[2][1] * translation[1] + m[2][2] * translation[2] + m[2][3];
	result[3][3] = m[3][0] * translation[0] + m[3][1] * translation[1] + m[3][2] * translation[2] + m[3][3];

	return result;
}

INLINE void glqMat4::ProjectVector (const glqVec4 &in, glqVec4 &out) const {

	out[0] = in[0] * m[0][0] + in[1] * m[1][0] + in[2] * m[2][0] + in[3] * m[3][0];
	out[1] = in[0] * m[0][1] + in[1] * m[1][1] + in[2] * m[2][1] + in[3] * m[3][1];
	out[2] = in[0] * m[0][2] + in[1] * m[1][2] + in[2] * m[2][2] + in[3] * m[3][2];
	out[3] = in[0] * m[0][3] + in[1] * m[1][3] + in[2] * m[2][3] + in[3] * m[3][3];
}

INLINE void glqMat4::UnprojectVector (const glqVec4 &in, glqVec4 &out) const {

	out[0] = in[0] * m[0][0] + in[1] * m[0][1] + in[2] * m[0][2] + in[3] * m[0][3];
	out[1] = in[0] * m[1][0] + in[1] * m[1][1] + in[2] * m[1][2] + in[3] * m[1][3];
	out[2] = in[0] * m[2][0] + in[1] * m[2][1] + in[2] * m[2][2] + in[3] * m[2][3];
	out[3] = in[0] * m[3][0] + in[1] * m[3][1] + in[2] * m[3][2] + in[3] * m[3][3];
}

INLINE const float *glqMat4::ToFloatPtr (void) const {

	return m[0].ToFloatPtr();
}

INLINE float *glqMat4::ToFloatPtr (void){

	return m[0].ToFloatPtr();
}


#endif	// __MATH_MATRIX_H__